package org.gc.dao.base;


import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.gc.common.entity.base.BaseUserEntity;
import org.gc.webapp.util.BizUtil;
import org.gc.webapp.util.page.BasePageSO;
import org.gc.webapp.util.page.PageList;
import org.gc.webapp.util.page.PageUtil;
import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.ObjectRetrievalFailureException;


/**
 * This class serves as the Base class for all other DAOs - namely to hold
 * common CRUD methods that they might all use. You should only need to extend
 * this class when your require custom CRUD logic.
 *
 * <p>To register this class in your Spring context file, use the following XML.
 * <pre>
 *      &lt;bean id="fooDao" class="oasis.dao.hibernate.GenericDaoHibernate"&gt;
 *          &lt;constructor-arg value="oasis.model.Foo"/&gt;
 *          &lt;property name="sessionFactory" ref="sessionFactory"/&gt;
 *      &lt;/bean&gt;
 * </pre>
 *
 * @param <T> a type variable
 * @param <PK> the primary key for that type
 */
public class BaseDaoImpl<T, PK extends Serializable> extends HibernateDaoSupport implements BaseDao<T, PK>{
    /**
     * Log variable for all child classes. Uses LogFactory.getLog(getClass()) from Commons Logging
     */
    protected final Log log = LogFactory.getLog(getClass());
    
    public final void setSessionFactory2(SessionFactory sessionFactory) {
        
    }
    private Class<T> persistentClass;

    /**
     * Constructor that takes in a class to see which type of entity to persist
     * @param persistentClass the class type you'd like to persist
     */
    public BaseDaoImpl(final Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    /* (non-Javadoc)
     * @see org.gc.dao.BaseDao#getAll()
     */
    @SuppressWarnings("unchecked")
    public List<T> getAll() {
        //父类为UserObject的entity查询时需要加上username属性限制
        if(this.persistentClass.getSuperclass() == BaseUserEntity.class){
            String username = BizUtil.getUsername();
            Criteria criteria = super.getHibernateTemplate().getSessionFactory().getCurrentSession().createCriteria(this.persistentClass);
            criteria.add(Restrictions.eq("username", username));
            criteria.addOrder(Order.desc("lastUpdateTime"));
            return criteria.list();
        }else{
            return super.getHibernateTemplate().loadAll(this.persistentClass);
        }
    }
    
    /* (non-Javadoc)
     * @see org.gc.dao.BaseDao#getPageList(org.gc.webapp.util.page.BasePageSO)
     */
    @SuppressWarnings("unchecked")
    public PageList<T> getPageList(BasePageSO so) {
        PageList<T> result = new PageList<T>();
        List<T> list;
        int fullListSize;

        //设置分页页码和每页对象数
        result.setPageNumber(so.getPageNumber());
        
        Criteria criteria = getSession().createCriteria(persistentClass);
        //父类为UserObject的entity查询时需要加上username属性限制
        if(this.persistentClass.getSuperclass() == BaseUserEntity.class
                || this.persistentClass.getSuperclass() == BaseUserEntity.class){
            String username = BizUtil.getUsername();
            criteria.add(Restrictions.eq("username", username));
            criteria.addOrder(Order.desc("lastUpdateTime"));
        }
        criteria.setFirstResult(PageUtil.getFirstResult(so));
        criteria.setMaxResults(so.getObjectsPerPage());
        
        list = criteria.list();
        
        //获取fullListSize
        criteria.setFirstResult(0);
        fullListSize = ((Integer) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
        
        result.setList(list);
        result.setFullListSize(fullListSize);
        
        return result;
    }
    /* (non-Javadoc)
     * @see org.gc.dao.BaseDao#get(PK)
     */
    @SuppressWarnings("unchecked")
    public T get(PK id) {
        T entity = (T) super.getHibernateTemplate().get(this.persistentClass, id);

        if (entity == null) {
            log.warn("Uh oh, '" + this.persistentClass + "' object with id '" + id + "' not found...");
            throw new ObjectRetrievalFailureException(this.persistentClass, id);
        }

        return entity;
    }
    /* (non-Javadoc)
     * @see org.gc.dao.BaseDao#get(PK, org.hibernate.LockMode)
     */
    @SuppressWarnings("unchecked")
    public T get(PK id, LockMode lockMode) {
        T entity = (T) super.getHibernateTemplate().get(this.persistentClass, id, lockMode);

        if (entity == null) {
            log.warn("Uh oh, '" + this.persistentClass + "' object with id '" + id + "' not found...");
            throw new ObjectRetrievalFailureException(this.persistentClass, id);
        }

        return entity;
    }
    /* (non-Javadoc)
     * @see org.gc.dao.BaseDao#exists(PK)
     */
    @SuppressWarnings("unchecked")
    public boolean exists(PK id) {
        T entity = (T) super.getHibernateTemplate().get(this.persistentClass, id);
        return entity != null;
    }

    /* (non-Javadoc)
     * @see org.gc.dao.BaseDao#save(T)
     */
    @SuppressWarnings("unchecked")
    public T save(T object) {
        //父类为UserObject的entity保存时需要自动记录username、createTime和lastUpdateTime属性
        if(object instanceof BaseUserEntity){
            String username = BizUtil.getUsername();
            BaseUserEntity userObject = (BaseUserEntity)object;
            userObject.setUsername(username);
            if(userObject.getId() == null){
                userObject.setCreateTime(new Date());
                userObject.setLastUpdateTime(userObject.getCreateTime());
            }else{
                userObject.setLastUpdateTime(new Date());
            }
        }
        return (T) super.getHibernateTemplate().merge(object);
    }

    /* (non-Javadoc)
     * @see org.gc.dao.BaseDao#remove(PK)
     */
    public void remove(PK id) {
        super.getHibernateTemplate().delete(this.get(id));
    }
    
   /* (non-Javadoc)
 * @see org.gc.dao.BaseDao#findByNamedQuery(java.lang.String, java.util.Map)
 */
   @SuppressWarnings("unchecked")
   public List<T> findByNamedQuery(
       String queryName, 
       Map<String, Object> queryParams) {
       String []params = new String[queryParams.size()];
       Object []values = new Object[queryParams.size()];
       int index = 0;
       Iterator<String> i = queryParams.keySet().iterator();
       while (i.hasNext()) {
           String key = i.next();
           params[index] = key;
           values[index++] = queryParams.get(key);
       }
       return getHibernateTemplate().findByNamedQueryAndNamedParam(
           queryName, 
           params, 
           values);
   }
   /* (non-Javadoc)
 * @see org.gc.dao.BaseDao#getByIds(java.util.List)
 */
@SuppressWarnings("unchecked")
    public List<T> getByIds(List<PK> ids) {
        Criteria criteria = getSession().createCriteria(persistentClass);
        if (ids != null && ids.size() > 0) {
            criteria.add(Expression.in("id", ids));
        }
        return criteria.list();
    }

    /* (non-Javadoc)
     * @see org.gc.dao.BaseDao#getBy(java.lang.String, java.lang.String)
     */
    @SuppressWarnings("unchecked")
    public T getBy(String propertyName, Object value) {
        Criteria criteria = getSession().createCriteria(persistentClass);
        criteria.add(Restrictions.eq(propertyName, value));
        List<T> list = criteria.list();
        if(list.size() > 0){
            return list.get(0);
        }else{
            return null;
        }
    }
    
    @SuppressWarnings("unchecked")
    public List<T> getListBy(String propertyName, Object value) {
        Criteria criteria = getSession().createCriteria(persistentClass);
        criteria.add(Restrictions.eq(propertyName, value));
        List<T> result = criteria.list();
        return result;
    }
}

